package cel

import (
	"log"

	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/common/types"
	"github.com/google/cel-go/common/types/ref"
	"github.com/iancoleman/strcase"
)

type CelEnv struct {
	env *cel.Env
}

func NewEnv() *CelEnv {
	// 下划线命名规则
	snakeFunction := cel.Function("snake", cel.Overload("snake_overload", []*cel.Type{types.StringType}, cel.StringType,
		cel.UnaryBinding(func(value ref.Val) ref.Val {
			input, ok := value.Value().(string)
			if !ok {
				return types.String("")
			}

			snakeStr := strcase.ToSnake(input)
			return types.String(snakeStr)
		}),
	))

	// 小驼峰命名规则
	camelFunction := cel.Function("camel", cel.Overload("camel_overload", []*cel.Type{cel.StringType}, cel.StringType,
		cel.UnaryBinding(func(value ref.Val) ref.Val {
			input, ok := value.Value().(string)
			if !ok {
				return types.String("")
			}

			snakeStr := strcase.ToLowerCamel(input)
			return types.String(snakeStr)
		}),
	))

	// 大驼峰命名规则
	pascalFunction := cel.Function("pascal", cel.Overload("pascal_overload", []*cel.Type{cel.StringType}, cel.StringType,
		cel.UnaryBinding(func(value ref.Val) ref.Val {
			input, ok := value.Value().(string)
			if !ok {
				return types.String("")
			}

			snakeStr := strcase.ToCamel(input)
			return types.String(snakeStr)
		}),
	))

	env, _ := cel.NewEnv(
		cel.Variable("name", cel.StringType),
		snakeFunction,
		camelFunction,
		pascalFunction,
	)

	return &CelEnv{
		env: env,
	}
}

type CelPrg struct {
	txt     string
	program cel.Program
}

// 编译 & 创建可执行程序
func (ce *CelEnv) Compile(txt string) (*CelPrg, error) {
	ast, issues := ce.env.Compile(txt)
	if issues != nil {
		log.Printf("编译错误: " + issues.Err().Error())
		return nil, issues.Err()
	}

	prg, e := ce.env.Program(ast)
	if e == nil {
		return &CelPrg{program: prg}, nil
	}

	return nil, e
}

func (prg *CelPrg) Eval(val any) (ref.Val, *cel.EvalDetails, error) {
	return prg.program.Eval(val)
}
